package yuchen.androidocr.imageUtil;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

/**
 * Created by yuchen on 5/15/16.
 */
public class ImageUtils {

    private Bitmap oringalBitmap;
    private int[] socelData;
    private int width;
    private int height;
    private int size;
    private int grayPixels[];
    private int outImageData[];
    private ImageThreshold imageThreshold = new ImageThreshold();

    public ImageUtils(int sobelData[], Bitmap orginalBitmap)
    {
        this.oringalBitmap = orginalBitmap;
        this.width = oringalBitmap.getWidth();
        this.height = orginalBitmap.getHeight();
        this.size = width * height;
        this.grayPixels = new int[size];
        this.outImageData = new int[size];
        this.socelData = sobelData;

    }



    public ArrayList getNumberArea(){
        int[] oringalData = new int[size];
        oringalBitmap.getPixels(oringalData,0,width,0,0,width,height);
        createGrayImage(oringalData);
        HashMap BFSearchResult = BFSearch(socelData);
        int seqSobel = (int)BFSearchResult.get("seq");
        int[] clusterSobel = (int[])BFSearchResult.get("cluster");
        dotSets setsSobel = genSets(clusterSobel,seqSobel,width,height);
        setsSobel.filterSobelSimple();
        if(setsSobel.getLength() <= 2){
            if(setsSobel.getLength() <=1){
                System.out.println("Unable to parse Image!");
                return null;
            }
            System.out.println("finish filter sobel");
        }else{
            System.out.println("continue filter sobel");
            setsSobel.SelectAreaSobel();
        }

        ArrayList digialArea = setsSobel.data.get(1).getArea();
        clusterSobel = setsSobel.fillSobel();
        int[] mask = setsSobel.getMask(clusterSobel);
        int mask_count =0;
        for(int i = 0; i < mask.length; i++)
        {
            if(mask[i] == 255)
            {
                mask_count ++;
            }
        }
        Log.d("mask_count","is "+ mask_count);
        maskImage(grayPixels,mask,width,height);
        int[] binary_data = (int[])imageThreshold.OTSUAlgorithm(grayPixels,width,height).get(0);
        HashMap resultOfBFWithMask = BFSearchWithMask(binary_data,mask);
        int seq = (int)resultOfBFWithMask.get("seq");
        int[] cluster = (int[])resultOfBFWithMask.get("cluster");
        dotSets sets = genSets(cluster,seq,width,height);
        sets.filter();
        sets.merge();
        sets.sort();
        String numResult = sets.reco(digialArea);
        ArrayList result = new ArrayList();
        result.add(numResult);
        Bitmap resultBitmap = Bitmap.createBitmap(binary_data,0,width,width,height,Bitmap.Config.RGB_565);
        result.add(resultBitmap);

        return result;
    }


    //深度优先搜索
    public HashMap BFSearch(int[] socelData) {
        int width = this.width;
        int height = this.height;
        HashMap matrix = new HashMap();
        HashMap sizemap = new HashMap();
        sizemap.put("width", width);
        sizemap.put("height", height);
        matrix.put("size", sizemap);
        int[] data = new int[width * height];
        matrix.put("data", data);
        //int imageData[] = socelData.getRGB(0, 0, width, height, null, 0, width);// 读进的图像的RGB值
        int imageData[] = socelData;
        boolean[] flags = new boolean[width * height];
        int[] cluster = new int[width * height];
        int i, j, ids;
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                ids = j + i * width;
                int point = Color.red(imageData[ids]);
                data[ids] = (point == 0) ? 1 : 0;
                matrix.put("data", data);
                cluster[ids] = data[ids];
                flags[ids] = false;
            }
        }

        int seq = 0;
        int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        //ArrayList queue = new ArrayList();
        Queue queue = new LinkedList<>();
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                ids = j + i * width;
                if (data[ids] == 1 && !flags[ids]) {
                    seq++;
                    flags[ids] = true;
                    cluster[ids] = seq;
                    int[] x_y = {i, j};
                    queue.add(x_y);
                    while (queue.size() != 0) {
                        int k, nj, ni, nids;
                        int[] pot = (int[]) queue.poll();
                        for (k = 0; k < 4; k++) {
                            ni = pot[0] + dirs[k][0];
                            nj = pot[1] + dirs[k][1];
                            nids = nj + ni * width;
                            if ((ni < height) && (ni >= 0) && (nj < width) && (nj >= 0) && (data[nids] == 1) && (!flags[nids])) {
                                flags[nids] = true;
                                cluster[nids] = seq;
                                int[] x_y2 = {ni, nj};
                                queue.add(x_y2);
                            }
                        }
                    }
                }
            }
        }

        HashMap result = new HashMap();
        result.put("cluster", cluster);
        result.put("seq", seq);

        return result;
    }

    public HashMap BFSearchWithMask(int[] imagedata, int[] mask){
        HashMap matrix = new HashMap();
        HashMap sizemap = new HashMap();
        sizemap.put("width", width);
        sizemap.put("height", height);
        matrix.put("size", sizemap);
        int[] data = new int[width * height];
        matrix.put("data", data);
        boolean[] flags = new boolean[width * height];
        int[] cluster = new int[width * height];
        int i, j, ids;
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                ids = j + i * width;
                int point = Color.red(imagedata[ids]);
                int mk = mask[ids];
                data[ids] =  (point == 0 && mk==255) ? 1 : 0;
                matrix.put("data",data);
                cluster[ids] = data[ids];
                flags[ids] = false;
            }
        }

        for (int mi = 0; mi < height; mi++) {
            for (int mj = 0; mj < width; mj++) {
                int mids = mj + mi * width;
                if(data[mids] == 1)
                {
                    Log.d("1","is " + mids);
                }
            }
        }

        int seq = 0;
        int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        Queue queue = new LinkedList<>();
        //宽度优先搜索
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                ids = j + i * width;
                if (data[ids] == 1 && !flags[ids]) {
                    seq++;
                    flags[ids] = true;
                    cluster[ids] = seq;
                    int[] x_y = {i,j};
                    queue.add(x_y);
                    while (queue.size() != 0) {
                        int k, nj, ni, nids;
                        int[] pot = (int[])queue.poll();
                        for (k = 0; k < 4; k++) {
                            ni = pot[0] + dirs[k][0];
                            nj = pot[1] + dirs[k][1];
                            nids = nj + ni * width;
                            if ((ni < height) && (ni >= 0) && (nj < width) && (nj >= 0) && (data[nids] == 1) && (!flags[nids])) {
                                flags[nids] = true;
                                cluster[nids] = seq;
                                int[] nx_ny = {ni,nj};
                                queue.add(nx_ny);
                            }
                        }
                    }
                }
            }
        }
        HashMap result = new HashMap();
        result.put("cluster", cluster);
        result.put("seq", seq);
        return result;
    }


    public dotSets genSets(int[] cluster, int seq, int width, int height) {
        dotSets sets = new dotSets(seq,width,height);
        sets.init();
        int i, j, ids;
        dataSet ds;
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                ids = j + i * width;
                ds = sets.data.get(cluster[ids]);
                int[] w_h = {j,i};
                ds.data.add(w_h);//i是高，j是宽
            }
        }
        sets.flush();
        return sets;
    }

    public int[] maskImage(int[] imagedata,int[] mask,int width,int height){
        int i, j, k,gray;
        for(i=0;i<height;i++){
            for(j=0;j<width;j++){
                k = j + i * width;
                int imagedata_rgb = imagedata[k] & 0xff;
                gray = imagedata_rgb & mask[k];
                int r = gray;
                int g = gray;
                int b = gray;
                int rgb = Color.rgb(r,g,b);
                imagedata[k] = rgb;
            }
        }
        return imagedata;
    }


    public void createGrayImage(int[] imageData) {
        int i, j, ids;
        for (j = 0; j < width * height; j++) {
            int r = Color.red(imageData[j]);
            int g = Color.green(imageData[j]);
            int b = Color.blue(imageData[j]);
            double gray = (r * 0.3 + g * 0.59 + b * 0.11);
            grayPixels[j] = (int)gray;
        }
    }


}
